﻿namespace NullObjExpml
{
    using System.Collections.Generic;
    using System;
    using System.Data.SqlTypes;

    /// <summary>
    /// Class which describes person (strong soft null)
    /// </summary>
    public class Person : IAssignable, INullable
    {
        #region Constructors

        public Person()
            : this(0, string.Empty, string.Empty, 0)
        {
        }

        public Person(int id, string fname, string lname, int age)
        {
            m_ID= id;
            m_FirstName= fname;
            m_LastName = lname;
            m_Age = age;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Id
        /// </summary>
        /// <exception cref="InvalidOperationException">If someone try to set a value for nullobject</exception>
        public int ID
        {
            get
            {
                return m_ID;
            }
            private set
            {
                if (IsNull)
                    throw new InvalidOperationException();

                m_ID = value;
            }
        }

        /// <summary>
        /// FirstName
        /// </summary>
        /// <exception cref="InvalidOperationException">If someone try to set a value for nullobject</exception>
        public string FirstName
        {
            get
            {
                return m_FirstName;
            }
            set
            {
                if (IsNull)
                    throw new InvalidOperationException();

                m_FirstName = value;
            }
        }

        /// <summary>
        /// LastName
        /// </summary>
        /// <exception cref="InvalidOperationException">If someone try to set a value for nullobject</exception>
        public string LastName
        {
            get
            {
                return m_LastName;
            }
            set
            {
                if (IsNull)
                    throw new InvalidOperationException();

                m_LastName = value;
            }
        }

        /// <summary>
        /// Age
        /// </summary>
        /// <exception cref="InvalidOperationException">If someone try to set a value for nullobject</exception>
        public int Age
        {
            get
            {
                return m_Age;
            }
            set
            {
                if (IsNull)
                    throw new InvalidOperationException();

                m_Age = value;
            }
        }

        #endregion

        #region IAssignable implementation

        /// <summary>
        /// Content transfer
        /// </summary>
        /// <param name="obj">Object that takes content</param>
        /// <exception cref="ArgumentNullException">If object, that takes content is a null object </exception>
        /// <exception cref="NotSupportedException">If object, that takes content isn't supported by method</exception>
        /// <exception cref="InvalidOperationException">If current object is nullable</exception>
        public void AssignTo(object obj)
        {
            if (IsNull)
                throw new InvalidOperationException();

            if (obj == null)
                throw new ArgumentNullException();

            if (obj is Person)
            {
                Person p = obj as Person;
                p.m_null = false;
                p.Age = Age;
                p.FirstName = FirstName;
                p.ID = ID;
                p.LastName = LastName;                

                return;
            }

            throw new NotSupportedException();
        }

        #endregion

        #region INullable Implementation

        public bool IsNull
        {
            get { return m_null; }
        }

        public static Person Null
        {
            get
            {
                Person p = new Person();
                p.m_null = true;
                return p;
            }
        }

        #endregion

        #region Private Fields

        private bool m_null = false;
        private int m_ID = default(int);
        private string m_FirstName = default(string);
        private string m_LastName = default(string);
        private int m_Age = default(int);

        #endregion
    }
}
